import * as vscode from "vscode";
import { getBox3MapUiList } from "@ap/user/map/getMapUiList";
import { CommandId } from "@ap/command";
import path from "path";
import { $context } from "@ap/extension";

interface Node {
  [key: string]: string;
}
// 定义一个枚举类型 nodeImg，用于集中管理节点图像的文件名
const nodeImg_dark: Node = {
  screen: "uiScreen-dark.svg",
  input: "uiInput-dark.svg",
  image: "uiImage-dark.svg",
  scrollBox: "uiScrollBox-dark.svg",
  text: "uiText-dark.svg",
  box: "uiBox-dark.svg",
};

const nodeImg_light: Node = {
  screen: "uiScreen-light.svg",
  input: "uiInput-light.svg",
  image: "uiImage-light.svg",
  scrollBox: "uiScrollBox-light.svg",
  text: "uiText-light.svg",
  box: "uiBox-light.svg",
};

const uiNodeType: Node = {
  screen: "UiScreen",
  input: "UiInput",
  image: "UiImage",
  scrollBox: "",
  text: "UiText",
  box: "UiBox",
};

/**
 * 表示 Visual Studio Code 中地图树视图的一个项目。
 * 继承 vscode.TreeItem 并添加特定于应用程序的属性，如 children。
 */
class MapTreeItem extends vscode.TreeItem {
  children?: MapTreeItem[];
  /**
   * 构造 MapTreeItem 的实例。
   */
  constructor(
    public readonly label: string,
    public readonly collapsibleState: vscode.TreeItemCollapsibleState,
    public readonly tooltip: string,
    public readonly type: string,
    public readonly description: string,
    public readonly parentId: string,
    public readonly id: string,
    public readonly iconPath: { light: vscode.Uri; dark: vscode.Uri },
  ) {
    super(label, collapsibleState);
  }
}

/**
 * 为 Visual Studio Code 中的地图树视图提供数据。
 * 实现 vscode.TreeDataProvider 接口以提供 getTreeItem、getChildren 和 refresh 功能。
 */
export default class UiMapTreeDataProvider
  implements vscode.TreeDataProvider<MapTreeItem>
{
  // 用于信号树数据已更改的 EventEmitter。
  private _onDidChangeTreeData: vscode.EventEmitter<MapTreeItem | undefined> =
    new vscode.EventEmitter<MapTreeItem | undefined>();

  // 当树数据发生变化时触发的事件。
  readonly onDidChangeTreeData: vscode.Event<MapTreeItem | undefined> =
    this._onDidChangeTreeData.event;

  // UI数据。
  uiData: Record<string, any> = {};

  /**
   * 获取给定元素的树项。
   * @param element 要获取树项的元素。
   * @returns 给定元素的树项。
   */
  getTreeItem(element: MapTreeItem): vscode.TreeItem {
    return element;
  }

  /**
   * 异步获取给定元素的子项。
   * 如果未指定元素，则获取树的根元素。
   * @param element 要获取其子项的元素。
   * @returns 一个 Promise，解析为表示子项的 MapTreeItem 数组。
   */
  async getChildren(element?: MapTreeItem | undefined): Promise<MapTreeItem[]> {
    if (!element) {
      const data = await getBox3MapUiList();
      if (data) {
        this.uiData = data;
        // 如果没有提供元素，则从地图列表构建树结构。
        const mapData = this.buildTree(data);

        return mapData;
      }
      return [];
    }
    // 返回指定元素的子项（如果存在）。
    return element.children || [];
  }

  /**
   * 从扁平的地图数据列表构造树结构。
   * @param data 表示地图数据的扩展快速选择项列表。
   * @returns 表示构造的树的根节点的 MapTreeItem 数组。
   */
  private buildTree(data: Record<string, any>): MapTreeItem[] {
    return data.ROOT_ID.childrenIds.map((item: string) => {
      const uiID = data[item];
      const treeItem = new MapTreeItem(
        uiID.name,
        uiID.childrenIds && uiID.childrenIds.length >= 1
          ? vscode.TreeItemCollapsibleState.Collapsed
          : vscode.TreeItemCollapsibleState.None,
        JSON.stringify(uiID.value.data),
        uiNodeType[uiID.value.type],
        uiID.default_ui ? "【默认】" : "",
        uiID.parentId,
        uiID.id,
        {
          light: vscode.Uri.file(
            path.join(
              $context.extensionPath,
              "image",
              nodeImg_light[uiID.value.type],
            ),
          ),
          dark: vscode.Uri.file(
            path.join(
              $context.extensionPath,
              "image",
              nodeImg_dark[uiID.value.type],
            ),
          ),
        },
      );
      if (uiID.childrenIds && uiID.childrenIds.length >= 1) {
        treeItem.children = this.buildTree2(data, uiID.childrenIds);
      }
      return treeItem;
    });
  }

  /**
   * 从子地图数据列表构造树结构。
   * @param data 表示子地图数据的记录列表。
   * @returns 表示构造的树节点的 MapTreeItem 数组。
   */
  private buildTree2(
    data: Record<string, any>,
    data2: string[],
  ): MapTreeItem[] {
    return data2.map((item: string) => {
      const uiID = data[item];
      const treeItem = new MapTreeItem(
        uiID.name,
        uiID.childrenIds && uiID.childrenIds.length >= 1
          ? vscode.TreeItemCollapsibleState.Collapsed
          : vscode.TreeItemCollapsibleState.None,
        JSON.stringify(uiID.value.data.data),
        uiNodeType[uiID.value.data.type],
        "",
        uiID.parentId,
        uiID.id,
        {
          light: vscode.Uri.file(
            path.join(
              $context.extensionPath,
              "image",
              nodeImg_light[uiID.value.data.type],
            ),
          ),
          dark: vscode.Uri.file(
            path.join(
              $context.extensionPath,
              "image",
              nodeImg_dark[uiID.value.data.type],
            ),
          ),
        },
      );
      if (uiID.childrenIds && uiID.childrenIds.length >= 1) {
        treeItem.children = this.buildTree2(data, uiID.childrenIds);
      }
      return treeItem;
    });
  }

  /**
   * 生成UI路径的函数
   *
   * 此函数根据给定的UI树项和UI映射树数据提供者生成一个UI路径字符串
   * UI路径用于在UI自动化测试或脚本中定位特定的UI元素
   *
   * @param ui 当前的UI树项，包含UI元素的信息及其在树中的位置
   * @returns 返回生成的UI路径字符串，用于定位特定UI元素
   */
  generateUiPath(ui: MapTreeItem, languageId?: string) {
    // 获取当前UI元素的父级UI元素
    let a = this.uiData[ui.parentId];
    // 创建一个数组，用于存储从当前UI元素到根元素的路径
    let b = [this.uiData[ui.id]];
    // 如果父级UI元素存在，则将其添加到路径数组中
    if (a) {
      b.push(a);
    }
    // 初始化路径字符串
    let c = "";
    // 遍历UI元素的父级链，直到达到根元素
    while (a && a.parentId !== "ROOT_ID") {
      a = this.uiData[a.parentId];
      b.push(a);
    }
    // 使用reduce函数反转路径数组并将其转换为字符串
    b = b.reduce((acc, curr) => [...acc, curr], []).reverse();
    let uiType = "",
      uiName = "";
    c = b
      .map((item) => {
        uiName = item.name;
        // 根据UI元素的类型生成不同的路径查找方法
        if (
          item &&
          item.value &&
          item.value.type !== "screen" &&
          item.value.data &&
          item.value.data.type !== "scrollBox"
        ) {
          uiType = uiNodeType[item.value.data.type];
          if (languageId === "typescript") {
            return `findChildByName<${uiNodeType[item.value.data.type]}>("${item.name}")?.`;
          } else {
            return `findChildByName("${item.name}")?.`;
          }
        } else {
          if (item && item.value && item.value.type !== "screen") {
            return `findChildByName("${item.name}")?.`;
          } else {
            if (item.default_ui) {
              return `ui.`;
            } else {
              return `UiScreen.getAllScreen().find(obj => obj.name === '${item.name}')?.`;
            }
          }
        }
      })
      .join("");
    // 移除字符串末尾的不需要的字符并返回生成的UI路径
    let text = c.slice(0, -2);
    if (languageId !== "typescript") {
      text =
        `/**
 * ${uiName}
 * @type ${uiType || "UiBox"}
 */
` + text;
    }

    return text;
  }

  /**
   * 刷新树数据，导致树视图重新获取数据。
   */
  refresh(): void {
    this._onDidChangeTreeData.fire(undefined);
  }
}
